网站导航:首页开源项目 USB开源项目:Easy USB 51 Programer  

目录导航

   
  1、项目简介
USB开发基础
1、USB接口的优点及开发难易度
2、USB设备的开发流程
3、USB接口芯片(USB控制器)的选择
4、了解USB的通讯过程
5、USB命令(请求)和USB描述符
6、实例讲解USB的枚举(配置)过程
准备工作
1、需要哪些工具
2、电路原理图
3、手工制作您的电路板
4、测试您的硬件
HID设备类
1、让PC机找到我们的硬件
2、如何成为一个HID设备(模拟鼠标)
3、如何成为一个HID设备(模拟键盘)
4、如何与HID设备通讯(一)
5、如何与HID设备通讯(二)
6、51编程器的实现
Windows USB 驱动程序(自定义设备)
1、Windows驱动开发基础
2、开发环境配置
3、第一个实例-Hello Wdm(一)
4、第一个实例-Hello Wdm(二)
5、真正的实例—驱动我们的实验板
6、真正的实例—测试驱动程序
7、真正的实例—控制LED及读取按键状态
8、如何编写应用程序
   

相关产品    淘宝网店
     
 

 
  更多...  
 
 
如何编写应用程序 查看/参与此开源项目相关讨论
 

说明:以下内容针对VC6环境

  虽然利用DriverStudio的工程向导为我们生成了测试程序示例,但它大量使用了DriverStudio自己的封装库,现在来介绍在不使用DriverStudio封装库的情况下如何编写测试程序。

1、打开设备的两种方式

  我们知道打开设备用CreateFile函数,其第一个参数应指向欲打开的USB设备,它可以是Device Interface,也可以是Device Symbolic Link(设备连接符或叫设备名)。要么用Interface打开USB设备,要么用Symbolic Link打开(不知正确与否),在利用DriverStudio工程向导生成时USB驱动程序的过程中可选择应用程序打开此USB设备的方式(见下图),在这时就确定了将来该用何种方式来打开设备。

1)用Interface方式打开设备

  首先取得设备的GUID(什么是GUID?请看这篇文章:USB编程之二(常见设备类型的GUID)),然后利用设备GUID来得到设备Interface,最后就可以用CreateFile函数来打开设备了。

  GUID由驱动程序定义,如上一节的驱动程序实例中对GUID的定义如下:

 
  1. #define Easy_USB_51_ProgramerDevice_CLASS_GUID \   
  2.  { 0x47589a1e, 0xad02, 0x455e, { 0xa9, 0xf7, 0xcc, 0xb2, 0xd5, 0xe, 0x68, 0x54 } }   

  还可以利用第三方工具取得设备GUID,如USBView,还有DriverStudio自带的Symbolic Viewer),下面是用Symbolic Viewer查得的上一节驱动实例的GUID

我们这里利用DEFINE_GUID宏来定义设备GUID,内容如下:

 
  1. DEFINE_GUID(Easy_USB_51_ProgramerDevice_CLASS_GUID,   
  2.     0xC713541C, 0x3C65, 0x474A, 0x8E, 0xBC, 0x25, 0x87, 0x51, 0x49, 0xD2, 0x05);   

DEFINE_GUID宏在initguid.h中定义的,所以需要在加入对此文件的引用:

 
  1. #include "initguid.h"  

  另外,我们将要用到的一些函数需要setupapi.h和setupapi.lib,它们是VC6自带的,所以需要添加对这两个文件的引用:

①#include "Setupapi.h"

②选择菜单“Project”->“Settings”,切换到“Link”页,在“Object/library modules”中填入:setupapi.lib

  好了,现在贴出以Interface方式打开设备的代码:

 
  1. //以Device Interface方式打开设备   
  2. void CWR_CtrlLEDDlg::OnOpendevByInterface()    
  3. {   
  4.     LONG                                ii = 0;   
  5.     HDEVINFO                            hDeviceInfo;   
  6.     DWORD                               bufferSize;   
  7.     SP_DEVICE_INTERFACE_DATA            interfaceData;   
  8.     PSP_DEVICE_INTERFACE_DETAIL_DATA    deviceDetail;   
  9.   
  10.      // Find all devices that have our interface   
  11.     hDeviceInfo = SetupDiGetClassDevs(   
  12.                     (LPGUID)&Easy_USB_51_ProgramerDevice_CLASS_GUID,       
  13.                     NULL,   
  14.                     NULL,   
  15.                     DIGCF_PRESENT | DIGCF_DEVICEINTERFACE   
  16.                     );   
  17.     if (hDeviceInfo == INVALID_HANDLE_VALUE)   
  18.     {   
  19.         AfxMessageBox("SetupDiGetClassDevs failed");   
  20.         return;   
  21.     }   
  22.   
  23.     // Setup the interface data struct   
  24.     interfaceData.cbSize = sizeof(interfaceData);   
  25.   
  26.     for (ii = 0;   
  27.         SetupDiEnumDeviceInterfaces(   
  28.             hDeviceInfo,   
  29.             NULL,   
  30.             (LPGUID)&Easy_USB_51_ProgramerDevice_CLASS_GUID,               
  31.             ii,   
  32.             &interfaceData);   
  33.         ++ii)   
  34.     {   
  35.         // Found our device instance   
  36.         if (!SetupDiGetDeviceInterfaceDetail(   
  37.             hDeviceInfo,   
  38.             &interfaceData,   
  39.             NULL,   
  40.             0,   
  41.             &bufferSize,   
  42.             NULL))   
  43.         {   
  44.             if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)   
  45.             {   
  46.                 TRACE("Error: couldn't get interface detail\n");   
  47.                    
  48.                 continue;   
  49.             }   
  50.         }   
  51.            
  52.         // Allocate a big enough buffer to get detail data   
  53.         deviceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(bufferSize);   
  54.         if (deviceDetail == NULL)   
  55.         {   
  56.             TRACE("Error: Buffer allocation failed\n");   
  57.             continue;   
  58.         }   
  59.            
  60.         // Setup the device interface struct   
  61.         deviceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);   
  62.            
  63.         // Try again to get the device interface detail info   
  64.         if (!SetupDiGetDeviceInterfaceDetail(   
  65.             hDeviceInfo,   
  66.             &interfaceData,   
  67.             deviceDetail,   
  68.             bufferSize,   
  69.             NULL,   
  70.             NULL))   
  71.         {   
  72.             TRACE("Error: SetupDiGetDeviceInterfaceDetail failed\n");   
  73.             free(deviceDetail);   
  74.             continue;   
  75.         }         
  76.                
  77.            
  78.         SetupDiDestroyDeviceInfoList(hDeviceInfo);   
  79.            
  80.         // Open handle to device   
  81.         m_hDev = CreateFile(   
  82.             deviceDetail->DevicePath,   
  83.             GENERIC_READ | GENERIC_WRITE,   
  84.             FILE_SHARE_READ | FILE_SHARE_WRITE,   
  85.             NULL,   
  86.             OPEN_EXISTING,   
  87.             0,   
  88.             NULL   
  89. );         
  90.            
  91.         // Free our allocated buffer   
  92.         free(deviceDetail);   
  93.            
  94.         if (m_hDev == INVALID_HANDLE_VALUE)   
  95.         {   
  96.             AfxMessageBox("Error: CreateFile failed\n");   
  97.             return;   
  98.         }   
  99.            
  100.         AfxMessageBox("设备成功打开!");   
  101.            
  102.         GetDlgItem(IDC_BTN_OPENDEV_BY_INTERFACE)->EnableWindow(FALSE);   
  103.         GetDlgItem(IDC_BTN_OPENDEV_BY_NAME)->EnableWindow(FALSE);   
  104.            
  105.         EnableControl(TRUE);   
  106.     }   
  107. }   

2)用Symbolic Link方式打开设备

  Driver Studio通过KUnitizedName函数生成设备的Symbolic Link,我们再利用CreateFile来打开设备,其一般形式为:

 
  1. hDevice = CreateFile("\\\\.\\OMNIPORT3",   
  2.          GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,   
  3.          NULL,    
  4. OPEN_EXISTING,    
  5. FILE_ATTRIBUTE_NORMAL ,   
  6. NULL);   

其中前缀“\\\\.\\”表示Createfile试图打开一个设备,然后紧跟设备名,其设备名可以利用DDK提供的“Device Tree”工具来查询,也可以查看DriverStudio向导生成的代码中KUnitizedName实例代码(位于AddDevice功能函数内),如果第一个参数为:L”TestDevice”,则设备名一般应为TestDevice0

  在上一节实例中生成的驱动程序是以Interface方式打开的,现在我们重新配置此项目,在配置向导第“Step 12 of 14”中,打开设备(Open Device)选择“Symbolic Link”选项,并填写Symbolic Link的值为:Easy_USB_51_Programer_SymbolicDevice:

下载编译后驱动

下载驱动源码(需要放到C:\Easy_USB_51_Programer_Symbolic目录)

  安装驱动程序,然后就可以用Symbolic Link的方式打开设备了,而Symbolic Link的值就应该为Easy_USB_51_Programer_SymbolicDevice0,这个值在配置向导第“Step 12 of 14”中已经填好(但其后要加“0”),通过查看驱动源程序也可以得到(位于AddDevice功能函数的KUnitizedName实例代码的第一个参数),也可用第三方工具如Symbolic Link Viewer查询,下图是利用DriverStudio提供的Symbolic Link Viewer工具查询到的Symbolic Link值:

  好了,现在贴出以Symbolic Link方式打开设备的代码:

 
  1. //利用Symbolic link来打开设备   
  2. void CWR_CtrlLEDDlg::OnOpendevBySymbolicLink()    
  3. {   
  4.     char *sLinkName = "\\\\.\\Easy_USB_51_Programer_SymbolicDevice0";   
  5.   
  6.     m_hDev  = CreateFile(sLinkName,   
  7.                       GENERIC_READ | GENERIC_WRITE,   
  8.                       FILE_SHARE_READ,   
  9.                       NULL,   
  10.                       OPEN_EXISTING,   
  11.                       0,   
  12.                       NULL);       
  13.        
  14.     if (m_hDev == INVALID_HANDLE_VALUE)   
  15.     {   
  16.         AfxMessageBox("Error: CreateFile failed");   
  17.         return;   
  18.     }   
  19.   
  20.     AfxMessageBox("设备成功打开!");   
  21. }   

2、读写设备

  读写设备除了可以通过WriteFile和ReadFile函数以外,还可以利用DeviceIoControl函数。WriteFile最终会调用驱动程序的IRP_MJ_READ实例代码(DriverStudio里是Write实例函数),ReadFile最终会调用驱动程序的IRP_MJ_ WRITE实例代码(DriverStudio里是Read实例函数),而DeviceIoControl最终会调用驱动程序的IRP_MJ_DEVICE_CONTROL实例代码(DriverStudio里是DeviceControl)。

  DeviceIoControl的第二个参数为操作代码,在驱动程序里的定义形如IOCTL_XXXX格式,对于自定义的设备操作代码,一般用CTL_CODE宏定义,我们需要拷贝上一节驱动程序中对IOCTL_LED和IOCTL_GET_KEY两个操作代码的定义(在使用前需要包含头文件:#include "Winioctl.h")

 
  1. #define IOCTL_LED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA)   
  2. #define IOCTL_GET_KEY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)   

  下面放上利用MFC编写的一个基于对话的程序,它主要实现与上一节中测试程序相似的功能(通过端点2读写数据,通过控制端点控制扩展板EXT-BOARD-A上的LED状态,通过控制端点读取扩展板EXT-BOARD-A上的按键的状态),另外还测试了两种打开设备的方式(设备安装驱动程序后就决定了设备只能以某一种方式打开,用不正确的方式打开会报错)。

                           应用程序界面

(呵呵,我已经投PCB了,所以没有用手工制作的那个原始东东来展示)

编译好的应用程序
应用程序源代码

这里再次放上下位机的固件程序及其源代码,还有两种以不同方式打开设备的Windows驱动程序及源代码
下位机固件源代码
Windows驱动程序
(只能以Interface方式打开)
Windows驱动程序源代码(只能以Interface方式打开)
Windows驱动程序(只能以Symbolic Link方式打开)
Windows驱动程序源代码(只能以Symbolic Link方式打开)
 

 
 
 
本站程序由百合电子工作室开发和维护
Copyright @ baihe electric studio
渝ICP备09006681号-4